﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LCA.Community.DAL.Interfaces;
using LCA.Community.DAL.Model;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace LCA.Community.DAL
{
    /// <summary>
    /// The repository for users data manipualtion.
    /// </summary>
    public class UsersRepository : BaseRepository<User>, IUsersRepository
    {
        #region Fields
        private IHospitalsRepository _hospitalRepository;
        private IHospitalPatientsRepository _hospitalPatientsRepository;
        private IFriendshipsRepository _friendshipRepository;
        private IGroupMembershipsRepository _groupMembershipRepository;
        private IAnswersRepository _answersRepository;
        private IAnswersVotesRepository _answersVotesRepository;
        private IPostsRepository _postRepository;
        private ICommentsRepository _commentsRepository;
        private IHelpRelationshipsRepository _helprelationshipsRepository;
        private IPostVotesRepository _postVotesRepository;
        private IMessagesRepository _messageRepository;
        private IMessagesRecipentsRepository _messagesRecipentsRepository;
        private IPhrasesRepository _phrasesRepository;
        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="UsersRepository"/> class.
        /// </summary>
        /// <param name="dataServiceContext">The data service context.</param>
        /// <param name="hospitalRepository">The hospital repository.</param>
        /// <param name="hospitalsPatientsRepository">The hospitals patients repository.</param>
        /// <param name="friendshipRepository">The friendship repository.</param>
        public UsersRepository(IDataServiceContext<User> dataServiceContext, HospitalsRepository hospitalRepository, IHospitalPatientsRepository hospitalsPatientsRepository, IFriendshipsRepository friendshipRepository, IGroupMembershipsRepository groupMembershipRepository, IAnswersRepository answersRepository, ICommentsRepository commentsRepository, IPostsRepository postsRepository, IAnswersVotesRepository answersVotesRepository, IHelpRelationshipsRepository helprelationshipsRepository, IMessagesRepository messageRepository, IMessagesRecipentsRepository messageRecipentsRepository, IPostVotesRepository postVotesRepository, IPhrasesRepository phrasesRepository)
            :base(dataServiceContext)
        {
            _groupMembershipRepository = groupMembershipRepository;
            _hospitalRepository = hospitalRepository;
            _hospitalPatientsRepository = hospitalsPatientsRepository;
            _friendshipRepository = friendshipRepository;
            _answersRepository = answersRepository;
            _postRepository = postsRepository;
            _commentsRepository = commentsRepository;
            _answersVotesRepository = answersVotesRepository;
            _helprelationshipsRepository = helprelationshipsRepository;
            _messageRepository = messageRepository;
            _messagesRecipentsRepository = messageRecipentsRepository;
            _postVotesRepository = postVotesRepository;
            _phrasesRepository = phrasesRepository;
        }

        /// <summary>
        /// Deletes the specified user.
        /// </summary>
        /// <param name="entity">The user.</param>
        public override void Delete(User entity)
        {
            base.Delete(entity);

            _groupMembershipRepository.DeleteAllUserMemberships(entity.RowKey);
            _answersRepository.DeleteAllUserAnswers(entity.RowKey);
            _postRepository.DeleteAllUserPosts(entity.RowKey);
            _commentsRepository.DeleteAllUserComments(entity.RowKey);
            _answersVotesRepository.DeleteAllUserVotes(entity.RowKey);
            _friendshipRepository.DeleteAllUserFriendShips(entity.RowKey);
            _helprelationshipsRepository.DeleteAllUserHelpRelationships(entity.RowKey);
            _hospitalPatientsRepository.DeleteUserAsPatient(entity.RowKey);
            _postVotesRepository.DeleteAllPostVotesFromUser(entity.RowKey);
        }

        /// <summary>
        /// Gets the message recipents.
        /// </summary>
        /// <param name="messageID">The message ID.</param>
        /// <returns>The recipents.</returns>
        public List<User> GetMessageRecipents(string messageID)
        {
            return (from mr in _messagesRecipentsRepository.Entities
                    where mr.Message == messageID
                    select Get(mr.Recipent)).ToList();
        }

        /// <summary>
        /// Gets the volunteers that are helping a user.
        /// </summary>
        /// <param name="userID">The user ID.</param>
        /// <returns>The volunteers helping the user</returns>
        public List<User> GetVolunteersOfUser(string userID)
        {
            return (from hr in _helprelationshipsRepository.Entities
                    where hr.User == userID
                    select Get(hr.Volunteer)).ToList();
        }

        /// <summary>
        /// Gets the name of the user containing the name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns>The list of users containing the name.</returns>
        public List<User> GetUserContainingName(string name)
        {
            return Entities.Where(u => u.Alias.ToLower().Contains(name.ToLower())).ToList();
        }

        /// <summary>
        /// Gets the helped people by user.
        /// </summary>
        /// <param name="userID">The user ID.</param>
        /// <returns></returns>
        public List<User> GetHelpedPeopleByUser(string userID)
        {
            return (from hr in _helprelationshipsRepository.Entities
                    where hr.Volunteer == userID
                    select Get(hr.User)).ToList();
        }

        /// <summary>
        /// Gets the user avatar URL.
        /// </summary>
        /// <param name="userID">The user ID.</param>
        /// <returns></returns>
        public string GetUserAvatarUrl(string userID)
        {
            return (from user in Entities
                    where user.RowKey == userID
                    select user.Avatar).FirstOrDefault();
        }

        /// <summary>
        /// Gets the user hospital.
        /// </summary>
        /// <param name="userID">The user ID.</param>
        /// <returns></returns>
        public Hospital GetUserHospital(string userID)
        {
            return (from hospital in _hospitalRepository.Entities
                    from hp in _hospitalPatientsRepository.Entities
                    where hp.Hospital == hospital.RowKey && hp.Patient == userID
                    select hospital).FirstOrDefault();
        }

        /// <summary>
        /// Gets the user by live ID.
        /// </summary>
        /// <param name="liveID">The live ID.</param>
        /// <returns></returns>
        public User GetUserByLiveID(string liveID)
        {
            return (from user in Entities
                    where user.LiveID == liveID
                    select user).FirstOrDefault();
        }

        /// <summary>
        /// Gets the user friends.
        /// </summary>
        /// <param name="userID">The user ID.</param>
        /// <returns></returns>
        public List<User> GetUserFriends(string userID)
        {
            return (from frienship in _friendshipRepository.Entities
                    where frienship.User == userID
                    select Get(frienship.Friend)).ToList();
        }

        /// <summary>
        /// Determines whether is a user name used.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns>
        /// 	<c>true</c> if is the user name used; otherwise, <c>false</c>.
        /// </returns>
        public bool IsUserNameUsed(string userName)
        {
            return (from user in Entities
                    where user.RowKey == userName
                    select user).Any();
        }

        /// <summary>
        /// Gets the volunteer by city.
        /// </summary>
        /// <param name="city">The city.</param>
        /// <returns>Volunteers from the city.</returns>
        public List<User> GetVolunteerByCity(string city)
        {
            return Volunteers.Where(v => v.City == city).ToList();
        }

        /// <summary>
        /// Gets the recent users.
        /// </summary>
        /// <value>The recent users.</value>
        public List<User> RecentUsers
        {
            get 
            { 
                return Entities.OrderByDescending(u => u.Timestamp).Take(10).ToList(); 
            }
        }

        /// <summary>
        /// Gets the volunteers.
        /// </summary>
        /// <value>The volunteers.</value>
        public List<User> Volunteers
        {
            get
            {
                return Entities.Where(u => u.Volunteer).ToList();
            }
        }

        /// <summary>
        /// Gets the non anonymous users.
        /// </summary>
        public List<User> NonAnonymousUsers
        {
            get
            {
                return Entities.Where(u => !u.Anonymous).ToList();
            }
        }
    }
}
